package com.kmxd.ams.app.event.copy.command;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.arrange.IVolumeSvc;
import com.kmxd.ams.client.arrange.dto.DocumentCopyDTO;
import com.kmxd.ams.client.arrange.dto.OptVolumeDTO;
import com.kmxd.ams.client.arrange.dto.VolumeCopyDTO;
import com.kmxd.ams.client.logs.ILogArchiveSvc;
import com.kmxd.ams.client.logs.dto.LogArchiveQueryDTO;
import com.kmxd.ams.client.logs.vo.LogArchiveListVO;
import com.kmxd.ams.core.common.bo.LoginUser;
import com.kmxd.ams.core.common.constant.Constants;
import com.kmxd.ams.core.common.enums.ArchManageEnum;
import com.kmxd.ams.core.common.enums.ArchOpEnum;
import com.kmxd.ams.core.common.enums.ArchOperateTitleOptionsEnum;
import com.kmxd.ams.core.common.enums.ArchStatusEnum;
import com.kmxd.ams.core.util.ConvertUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.archive.entity.ArchiveType;
import com.kmxd.ams.infra.arrange.entity.Document;
import com.kmxd.ams.infra.arrange.entity.Volume;
import com.kmxd.ams.infra.logs.entity.LogArchive;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 案卷复制操作
 *
 * @author nickbi
 */
@Slf4j
@Component
@AllArgsConstructor
public class VolumeCopyCmd {
  private final DocumentCopyCmd documentCopyCmd;
  private final IVolumeSvc volumeSvc;
  private final ArchiveMetaFieldCmd archiveMetaFieldCmd;
  private final IArchiveTypeSvc archiveTypeSvc;
  private final ILogArchiveSvc logArchiveSvc;

  /** 复制电子文件 */
  @Transactional(rollbackFor = Exception.class)
  public void copy(VolumeCopyDTO req, String saToken) throws Exception {
    log.debug("start copy volume: {} ", req);
    Volume qry = new Volume();
    qry.setArchTypeId(req.getArchTypeId());
    qry.setTableId(req.getTableId());
    qry.setId(req.getId());
    Volume oldArch = volumeSvc.view(qry);
    Map<String, String> metaFieldMap =
        archiveMetaFieldCmd.getMetaFieldMap(req.getTableId(), req.getNewVolumeTableId());
    // 元数据对应为空，则直接按名称复制
    Volume newVolume =
        null == metaFieldMap
            ? ConvertUtil.toBean(oldArch, Volume.class)
            : ConvertUtil.toMetaFieldBean(oldArch, metaFieldMap, Volume.class);

    // 1条目信息，1条目信息+电子文件
    if (req.getTitleOptions().equals(ArchOperateTitleOptionsEnum.APPEND_COPY.getCode())) {
      newVolume.setTitle(Constants.COPY_PREFIX + newVolume.getTitle());
    }
    newVolume.setStatus(req.getStatus());
    // 重置档号等信息
    newVolume.setId(null);
    newVolume.setArchCode(null);
    newVolume.setVolSequence(null);

    // 复制到其他门类时，修改门类及数据表信息
    if (Objects.nonNull(req.getNewArchTypeId())) {
      newVolume.setArchTypeId(req.getNewArchTypeId());
    } else {
      newVolume.setArchTypeId(req.getArchTypeId());
    }

    oldArch.setArchTypeId(req.getArchTypeId());
    // 复制到其他门类时，设置新的案卷信息
    if (Objects.nonNull(req.getNewVolumeTableId())) {
      newVolume.setTableId(req.getNewVolumeTableId());
    } else {
      newVolume.setTableId(req.getTableId());
    }
    if (req.getOpType().equals(ArchOpEnum.COPY.getCode())) {
      newVolume.setArchCode(null);
    } else {
      if (null != req.getCleanArchCode() && req.getCleanArchCode()) {
        newVolume.setArchCode(null);
      }
    }

    if (Objects.nonNull(req.getNewProjectId())) {
      newVolume.setProjId(req.getNewProjectId());
      newVolume.setProjCode(req.getNewProjectCode());
    }
    volumeSvc.add(newVolume);
    log.debug(" copy volume: {} ", newVolume);
    // 如果是移动，删除原文件
    if (req.getOpType().equals(ArchOpEnum.MOVE.getCode())) {
      // 此处使用真删除
      volumeSvc.cleanTrash(BeanUtil.copyProperties(req, OptVolumeDTO.class));
    }

    Document documentQry = new Document();
    documentQry.setTableId(req.getDocTableId());
    documentQry.setVolId(oldArch.getId());
    List<Document> documentList = documentCopyCmd.list(documentQry);
    if (null == documentList || documentList.isEmpty()) {

      return;
    }

    DocumentCopyDTO documentCopyDTO = ConvertUtil.toBean(req, DocumentCopyDTO.class);
    documentCopyDTO.setNewVolId(newVolume.getId());
    // 转门类的时候，需要传递设置新的文件表名
    documentCopyDTO.setTableId(req.getDocTableId());

    for (Document document : documentList) {
      documentCopyDTO.setId(document.getId());
      log.debug(" copy volume include document {} ", documentCopyDTO);
      documentCopyCmd.copy(documentCopyDTO, saToken);
    }
    saveLog(req, oldArch, newVolume, saToken);
  }

  public void saveLog(VolumeCopyDTO req, Volume old, Volume newVol, String saToken) {
    LogArchiveQueryDTO qryLog = new LogArchiveQueryDTO();
    qryLog.setArchId(old.getId());
    List<LogArchiveListVO> logList = logArchiveSvc.selectList(qryLog);
    if (req.getOpType().equals(ArchOpEnum.COPY.getCode())) {
      List<LogArchive> newLogList =
          logList.stream()
              .map(
                  item -> {
                    LogArchive log = ConvertUtil.toBean(item, LogArchive.class);
                    log.setArchId(newVol.getId());
                    log.setId(null);
                    return log;
                  })
              .collect(Collectors.toList());
      LogArchive copyLog = ConvertUtil.toBean(newVol, LogArchive.class);
      copyLog.setArchId(newVol.getId());
      copyLog.setType(ArchManageEnum.BECOMING.getType());
      setUserInfo(saToken, copyLog);
      if (ObjectUtil.equals(old.getArchTypeId(), newVol.getArchTypeId())) {
        copyLog.setActionDescription(
            StrUtil.format("新增档案 （从\"{}\"）复制", ArchStatusEnum.convert(old.getStatus()).getDesc()));
      } else {
        ArchiveType oldArchType = archiveTypeSvc.getById(old.getArchTypeId());
        ArchiveType newArchType = archiveTypeSvc.getById(newVol.getArchTypeId());
        copyLog.setActionDescription(
            StrUtil.format("（从\"{}\"）复制 到 \"{}\"", oldArchType.getName(), newArchType.getName()));
        copyLog.setActionDescription(
            String.format(
                "move data from archTypeId: %s, tableId: %s, dataId: %s to archTypeId: %s, "
                    + "tableId: %s, dataId: %s",
                oldArchType.getId(),
                old.getTableId(),
                old.getId(),
                newArchType.getId(),
                newVol.getTableId(),
                newVol.getId()));
      }
      newLogList.add(copyLog);
      logArchiveSvc.saveBatch(newLogList);
    }

    if (req.getOpType().equals(ArchOpEnum.MOVE.getCode())) {
      ArchiveType oldArchType = archiveTypeSvc.getById(old.getArchTypeId());
      ArchiveType newArchType = archiveTypeSvc.getById(newVol.getArchTypeId());
      LogArchive moveLog = ConvertUtil.toBean(newVol, LogArchive.class);
      moveLog.setArchId(newVol.getId());
      moveLog.setType(ArchManageEnum.ARRANGE.getType());
      setUserInfo(saToken, moveLog);
      moveLog.setActionDescription(
          StrUtil.format("（从\"{}\"）移动 到 \"{}\"", oldArchType.getName(), newArchType.getName()));
      moveLog.setActionDescription(
          String.format(
              "move data from archTypeId: %s, tableId: %s, dataId: %s to archTypeId: %s, tableId:"
                  + " %s, dataId: %s",
              oldArchType.getId(),
              old.getTableId(),
              old.getId(),
              newArchType.getId(),
              newVol.getTableId(),
              newVol.getId()));
      logArchiveSvc.save(moveLog);
    }
  }

  private void setUserInfo(String saToken, LogArchive log) {
    log.setComId(SecurityUtil.getCropId(saToken));
    log.setFondsId(SecurityUtil.getFondsId(saToken));
    log.setUserId(SecurityUtil.getUserId(saToken));
    LoginUser loginUser = SecurityUtil.getLoginUser(saToken);
    log.setDeptId(Objects.requireNonNull(loginUser).getDeptId());
    log.setDeptName(loginUser.getDeptName());
    log.setRoleId(loginUser.getRoleId());
    log.setUserName(loginUser.getUsername());
    log.setUserCode(loginUser.getSysUser().getAccount());
    log.setOpTime(new Date());
    log.setIp(loginUser.getIpAddress());
  }
}
